/**
 * P��klady pou�it� t��dy
 *  
 * SQLAritFunc2 fn = new SQLAritFunc2(new MSSQLDialect())</br>
 * .add(new Object[] {	new UniQLBracketExpr().add(new Object[] {"1", "-", "DISC1", "/", "100"})});</br>
 *
 * v�stup: ((1 - [DISC1] / 100.000000) + [tbl0].[DOUBLE])</br>
 *
 * SQLAritFunc2 fn = new SQLAritFunc2(new MSSQLDialect())</br>
 * .add(new Object[] {"MUNIT_PRICE", "*"})</br>
 * .addBrackets(new Object[] {"1", "-", "DISC1", "/", "100.000000"})</br>
 * .add(new Object[] {"+", "TBL0.DOUBLE"});</br>
 *
 * v�stup: ([MUNIT_PRICE] * (1 - [DISC1] / 100.000000) + [tbl0].[DOUBLE])</br>
 *
 * SQLAritFunc2 fn = new SQLAritFunc2(new MSSQLDialect())</br> 
 * .addBrackets(new Object[] {"1", "-", new UniQLColumn("DISC1"), "/", "100.000000"})</br>
 * .add(new Object[] {"+", "TBL0.DOUBLE"});</br>
 *
 * v�stup: ((1 - [DISC1] / 100.000000) + [tbl0].[DOUBLE])</br>
 *
 * @author www.smart4web.cz
 * 
 */
package cz.acies.uniql.sql.functions;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;

import org.dom4j.Element;
import org.dom4j.dom.DOMElement;


import cz.acies.uniql.dialect.Dialect;
import cz.acies.uniql.dialect.MSSQLDialect;
import cz.acies.uniql.sql.UniQLExpr;
import cz.acies.uniql.sql.element.UniQLColumn;
import cz.acies.uniql.sql.element.UniQLCondition;
import cz.acies.uniql.sql.element.UniQLCriterion;
import cz.acies.uniql.sql.element.UniQLValue;
import cz.acies.utils.StringUtils;

public class SQLAritFunc2 extends SQLFunc
{
	private static final long serialVersionUID = 4825356582891310810L;

	public static void main(String[] args) {
		try {
			SQLAritFunc2 fn = new SQLAritFunc2(new MSSQLDialect())
			.add(new Object[] {"MUNIT_PRICE", "*"})
			.addBrackets(new Object[] {"1", "-", "DISC1", "/", "100.000000"})
			.add(new Object[] {"+", "TBL0.DOUBLE"});
			
			System.out.println(fn.translate());
		} catch (Exception exc) {
			exc.printStackTrace();
		}
	}
	
	private static final int PLUS 	= 0; 	// "+"
	private static final int MINUS 	= 1; 	// "-"
	private static final int MULTI 	= 2; 	// "*"
	private static final int DIV 	= 3; 	// "/"
	
	private static LinkedHashMap<String, Integer> operators = new LinkedHashMap<String, Integer>();
	static {
		operators.put("+", new Integer(PLUS));
		operators.put("-", new Integer(MINUS));
		operators.put("*", new Integer(MULTI));
		operators.put("/", new Integer(DIV));
	}
	private static List<String> opidx = new ArrayList<String>(operators.keySet());
	
	private ArrayList<Object> parameters = new ArrayList<Object>();
	
	/**
	 * Kontruktuor tridy SQLAritFunc2 
	 */	
	public SQLAritFunc2() {
	}

	/**
	 * Konstruktor tridy SQLAritFunc2
	 * 
	 * @param dialect Objekt type Dialect
	 */	
	public SQLAritFunc2(Dialect dialect) {
		super(dialect);
	}

	@Deprecated
	public SQLAritFunc2(String name) {
		super();
		this.setName(name.toLowerCase());		
	}

	// -----  -----------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.element.UniQLExpr#translate()
	 */	
	public String translate() throws Exception {
		Dialect dialect = this.getDialect();
		StringBuilder sb = new StringBuilder();
		if (parameters.size() == 1 && parameters.get(0) instanceof UniQLBracketExpr ) {
			UniQLBracketExpr expr = (UniQLBracketExpr)parameters.get(0);
			expr.setUniQLProperties(this);
			return expr.translate();
		}
		for (Iterator<Object> iterator = parameters.iterator(); iterator.hasNext();) {
			Object obj = iterator.next();
			if (obj instanceof Integer) {
				sb.append(" "+opidx.get(((Integer)obj).intValue())+" ");
			} else if (obj instanceof UniQLExpr) {
				UniQLExpr expr = (UniQLExpr)obj;
				expr.setUniQLProperties(this);
				sb.append(expr.translate());
			} else {
				sb.append(obj.toString());
			}
		}
		return "(" + sb.toString() + ")";
	}
	
	/**
	 * 
	 * @param o
	 * @return
	 */
	public SQLAritFunc2 addBrackets(Object[] args) {
		UniQLBracketExpr expr = new UniQLBracketExpr().add(args);
		//expr.setDialect(getDialect());
		//expr.setAliasMap(getAliasMap());
		expr.setUniQLProperties(this);
		parameters.add(expr);
		return this;
	}
	
	/**
	 * 
	 * @param args
	 * @return
	 */
	public SQLAritFunc2 add(Object[] args) {
		for (Object obj : args) {
			if (obj instanceof String) {
				String s = ((String)obj).trim();
				if (operators.containsKey(((String) obj).trim())) {
					parameters.add(operators.get(s));
				} else {
					parameters.add(makeExpr(obj));
				}
			} else {
				parameters.add(makeExpr(obj));
			}
		}
		return this;
	}
	
	
	private UniQLExpr makeExpr(Object obj) {
		if (obj instanceof String) {
			String s = ((String)obj).trim();
			if (operators.containsKey(((String) obj).trim())) {
				return null;
			} else {
				UniQLExpr expr = null;
				if (s.matches(StringUtils.NUMERIC_PATTERN) ||
					s.matches(StringUtils.INTEGER_PATTERN) ||
					s.matches("\\'.*\\'")) {
					
					expr = new UniQLValue(obj.toString());						
				} else if (s.matches("\\w*?\\.?\\w+")) {
					expr = new UniQLColumn(obj.toString());	
				} else {
					expr = new UniQLValue(obj.toString());						
				}
				//expr.setDialect(getDialect());
				//expr.setAliasMap(getAliasMap());
				expr.setUniQLProperties(this);
				return expr; 
			}
		} else if (obj instanceof UniQLExpr) {
			//((UniQLExpr)obj).setDialect(getDialect());
			//((UniQLExpr)obj).setAliasMap(getAliasMap());
			((UniQLExpr)obj).setUniQLProperties(this);
			return ((UniQLExpr)obj);
		}
		return null;
	}

	// -----  -----------------------------------------------------------------
	
	/**
	 * @return the parameters
	 */
	public ArrayList<Object> getParameters() {
		return parameters;
	}

	/**
	 * @param parameters the parameters to set
	 */
	public void setParameters(ArrayList<Object> parameters) {
		this.parameters = parameters;
	}

	// -----  -----------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#transToXML()
	 */
	public String transToXML() throws Exception {
		DOMElement node = new DOMElement("SQLAritFunc2");
		transToXML(node);
		return node.asXML();
	}
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#transToXML(org.dom4j.dom.DOMElement)
	 */
	public DOMElement transToXML(DOMElement node) throws Exception {
		//String columnName = this.getName();
		node.setName("SQLAritFunc2");
		node.setAttribute("name", this.getName());
		if (parameters != null) {
			int size = parameters.size();
			for (int i = 0; i < size; i++) {
				Object obj = parameters.get(i);
				if (obj instanceof UniQLExpr) {
					UniQLExpr expr = (UniQLExpr)obj;
					DOMElement param = expr.transToXML(new DOMElement("UniQLExpr"));
					if (param != null) {
						node.appendChild(param);	
					}
				}
			}			
		}		
		return node;
	}
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#xmlToExpr(java.lang.String)
	 */
	public UniQLExpr xmlToExpr(String xml) throws Exception {
		System.out.println("SQLAritFunc2.xmlToExpr(xml)");
		return null;
	}

	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#xmlToExpr(org.dom4j.Element)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public UniQLExpr xmlToExpr(Element node) throws Exception {
		ArrayList<Element> params = new ArrayList<Element>(node.elements());
		String name = node.attributeValue("name");
		this.setName(name);
		for (int i = 0; i < params.size(); i++) {
			Element param = (Element)params.get(i);
			String nodename = param.getName();
			//System.out.println("SQLFunc.xmlToExpr().nodename = "+nodename);
			UniQLExpr expr = null; 
			if (nodename.trim().equals("UniQLColumn")) {
				expr = new UniQLColumn(getDialect()).xmlToExpr(param);
			} else if (nodename.trim().equals("UniQLValue")) {
				expr = new UniQLValue(getDialect()).xmlToExpr(param);
			} else if (nodename.trim().equals("UniQLCriterion")) {
				expr = new UniQLCriterion(getDialect()).xmlToExpr(param);	
			} else if (nodename.trim().equals("UniQLCondition")) {
				expr = new UniQLCondition(getDialect()).xmlToExpr(param);
			} else if (nodename.trim().equals("SQLFunc")) {
				expr = new SQLFunc(getDialect()).xmlToExpr(param);
			} else if (nodename.trim().equals("SQLAritFunc")) {
				expr = new SQLAritFunc(getDialect()).xmlToExpr(param);
			} else if (nodename.trim().equals("SQLAgregFunc")) {
				expr = new SQLAgregFunc(getDialect()).xmlToExpr(param);
			}
			if (expr != null) {
				this.addParam(expr);
			}
		}		
		return this;
	}

	//---------------------------------

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		return ""+this.getName()+" ("+this.getParameters() +")";
	}

}
